#include "datacenter.h"
#include  <QStandardPaths>
#include  <QFile>
#include  <QDir>
#include  <QJsonObject>
#include  <QJsonDocument>

namespace model
{

DataCenter* DataCenter::instance = nullptr;

DataCenter::DataCenter()
    :netClient(this)
{
    //此处把 hash 类型属性 new 出实例, 其他 Qlist类型的属性,暂时不实例化
    //主要是为了使用 nullptr 表示非法状态
    //对于hash 来说, 不关心整个 hash 是否是 nullptr, 而是关心, 某个key 对应的 value 是否存在
    //通过 key 是否存在, 也能表示该值是否有效
    recentMessage = new QHash<QString, QList<Message>>();
    memberList    = new QHash<QString, QList<UserInfo>>();
    unreadMessageCount = new QHash<QString, int>();
    loadDataFile();
}

void DataCenter::initDataFile()
{
    // 构造出文件的路径, 使用 appData 存储文件
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath +  + "/ChatClient.json";
    LOG() << "filePath= " << filePath;

    QDir dir;
    if (!dir.exists(basePath))
    {
        dir.mkpath(basePath);
    }

    //构造好文件路径之后,把文件创建出来
    //写方式打开, 并且写入初始内容
    QFile file (filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        LOG() << "打开文件失败";
        return;
    }
    // 打开成功, 写入初始内容
    QString data = "{\n\n}";
    file.write(data.toUtf8());
    file.close();

}

void DataCenter::saveDataFile()
{
    QString filePath  = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        LOG() << "文件打开失败" << file.errorString();
        return;
    }

    // 按照 json 格式来写入数据
    // 这个对象当作 map 一样来使用
    QJsonObject jsonObj;
    jsonObj["loginSessionId"] = loginSessionId;

    QJsonObject jsonUnread;
    for (auto it = unreadMessageCount->begin(); it != unreadMessageCount->end(); ++it )
    {   //QT 的迭代器使用细节和STL 略有差别, 此处不是使用 first / second 方式
        jsonUnread[it.key()] = it.value();
    }
    jsonObj["unread"] = jsonUnread;

    // 把JSON写入文件
    QJsonDocument jsonDoc(jsonObj);
    QString s = jsonDoc.toJson();
    file.write(s.toUtf8());

    // 关闭文件
    file.close();




}
 // 加载文件,在DataCenter被实例化就调用执行
void DataCenter::loadDataFile()
{
   // 确保在加载之前对文件进行初始化
   QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";
   QFileInfo fileInfo(filePath);
   //判断文件是否存在, 不存在就初始化, 并创建出新的空白的 json 文件
   if (!fileInfo.exists())
   {
       initDataFile();
   }

   // 读方式打开文件
   QFile file(filePath);
   if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
   {
       LOG() << "打开文件失败" << file.errorString();
       return;
   }

   // 读取文件内容, 解析为 JSON 对象
   QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
   if (jsonDoc.isNull())
   {
       LOG() << "解析 JSON 文件失败! JSON 文件格式有错误";
       file.close();
       return;
   }

   QJsonObject jsonObj = jsonDoc.object();
   this->loginSessionId = jsonObj["loginSessionId"].toString();
   LOG() << "loginSessionId=" << this->loginSessionId;

   this->unreadMessageCount->clear();
   QJsonObject jsonUnread = jsonObj["unread"].toObject();
   for (auto it = jsonUnread.begin(); it != jsonUnread.end(); ++it)
   {
       this->unreadMessageCount->insert(it.key(), it.value().toInt());
   }

   file.close();

}

void DataCenter::clearUnread(const QString &chatSessionId)
{
    (*unreadMessageCount)[chatSessionId] = 0;

    //手动保存结果到文件中
    saveDataFile();
}

void DataCenter::addUnread(const QString &chatSessionId)
{
    ++(*unreadMessageCount)[chatSessionId];

    //手动保存结果到文件
    saveDataFile();
}

int DataCenter::getUnread(const QString &chatSessionId)
{
    return (*unreadMessageCount)[chatSessionId];
}

void DataCenter::initWebsocket()
{
    netClient.initWebSocket();
}

void DataCenter::getMyselfAsync()
{
    // 注意 dataCenter 只是负责处理数据, 真正访问网络需要通过 NetClient
    netClient.getMyself(loginSessionId);
}

void DataCenter::resetMyself(std::shared_ptr<shiyue_im::GetUserInfoRsp> resp)
{
    if (myself == nullptr)
    {
        myself = new UserInfo();
    }
    const shiyue_im::UserInfo& userInfo = resp->userInfo();
    myself->load(userInfo);

}

UserInfo *DataCenter::getMyself()
{
    return myself;
}

void DataCenter::getFriendListAnsync()
{
    netClient.getFriendList(loginSessionId);
}

QList<UserInfo> *DataCenter::getFriendList()
{
    return friendList;
}

void DataCenter::resetFriendList(std::shared_ptr<shiyue_im::GetFriendListRsp> resp)

{
    if (friendList == nullptr)
    {
        friendList = new QList<UserInfo>();
    }

    friendList->clear();
    QList<shiyue_im::UserInfo>& friendListPB = resp->friendList();
    for (auto& f: friendListPB)
    {
        UserInfo userinfo;
        userinfo.load(f);
        friendList->push_back(userinfo);
    }

}

void DataCenter::getChatSessionListAsync()
{
    netClient.getChatSessionList(loginSessionId);
}

QList<ChatSessionInfo> *DataCenter::getChatSessionList()
{
    return chatSessionList;
}

void DataCenter::resetChatSessionList(std::shared_ptr<shiyue_im::GetChatSessionListRsp> resp)
{

    if (chatSessionList == nullptr)
    {
        chatSessionList = new QList<ChatSessionInfo>();
    }
    LOG() << "处理resp";

    chatSessionList->clear();

    auto& chatSessionListPB = resp->chatSessionInfoList();
    LOG() << "处理结束";
    for (auto& c: chatSessionListPB)
    {

        ChatSessionInfo chatSessionInfo;

        chatSessionInfo.load(c);


        chatSessionList->push_back(chatSessionInfo);
    }
}

void DataCenter::getApplyListAsync()
{
    netClient.getApplyList(loginSessionId);
}

QList<UserInfo> *DataCenter::getApplyList()
{
    return applyList;
}

void DataCenter::resetApplyList(std::shared_ptr<shiyue_im::GetPendingFriendEventListRsp> resp)
{
    if (applyList == nullptr)
    {
        applyList = new QList<UserInfo>();
    }
    applyList->clear();

    auto& eventList = resp->event();
    for (auto& event: eventList)
    {
        UserInfo userInfo;
        userInfo.load(event.sender());
        applyList->push_back(userInfo);
    }
}

QList<Message>* DataCenter::getRecentMessageList(const QString &chatSessionId)
{
    if (!recentMessage->contains(chatSessionId))
    {
        return nullptr;
    }
    return &(*recentMessage)[chatSessionId];
}

void DataCenter::getRecentMessageListAsync(const QString &chatSessionId, bool updateUi)
{
    netClient.getRcentMessageList(loginSessionId, chatSessionId, updateUi);
}

void DataCenter::resetRecentMessageList(const QString &chatSessionId, std::shared_ptr<shiyue_im::GetRecentMsgRsp> resp)
{
    // 拿到 chatSessionId对应的消息列表,并清空
    //此处务必是引用类型,才能修改哈希表内容
    QList<Message>& messageList  = (*recentMessage)[chatSessionId];

    messageList.clear();

    // 遍历响应结果列表
    for (auto& m : resp->msgList())
    {
        Message message;
        message.load(m);
        messageList.push_back(message);
    }




}

void DataCenter::searchUserAsync(const QString &searchKey)
{
    netClient.searchUser(loginSessionId, searchKey);
}

void DataCenter::resetSearchUserResult(const QList<shiyue_im::UserInfo> &userList)
{
    if (searchUserResult == nullptr) {
        searchUserResult = new QList<UserInfo>();
    }
    searchUserResult->clear();

    for (const auto & u: userList) {
        UserInfo userInfo;
        userInfo.load(u);
        searchUserResult->push_back(userInfo);
    }
}

QList<UserInfo> *DataCenter::getSearchUserResult()
{
    return searchUserResult;
}

void DataCenter::searchMessageAsync(const QString &searchKey)
{
    //搜索的历史消息,根据会话来组织
    netClient.searchMessage(loginSessionId, this->currentChatSessionId, searchKey);
}

void DataCenter::searchMessageByTimeAsync(const QDateTime &begTime, const QDateTime &endTime)
{
    netClient.searchMessageByTime(loginSessionId, currentChatSessionId, begTime, endTime);
}

void DataCenter::resetSearchMessageResult(const QList<shiyue_im::MessageInfo> &msgList)
{
    if (this->searchMessageResult == nullptr) {
        this->searchMessageResult = new QList<Message>();
    }
    this->searchMessageResult->clear();
    for (const auto& m : msgList) {
        Message message;
        message.load(m);
        searchMessageResult->push_back(message);
    }
}

QList<Message> *DataCenter::getSearchMessageResult()
{
    return searchMessageResult;
}

void DataCenter::userLoginAsync(const QString &username, const QString &password)
{
    //登录操作,没有loginSessionId
    //登录成功之后,服务器才会返回loginSessionId;
    netClient.userLogin(username, password);
}

void DataCenter::resetLoginSessionId(const QString &loginSessionId)
{
    this->loginSessionId = loginSessionId;
    //一旦会话id改变,就需要保存到硬盘上
    saveDataFile();
}

void DataCenter::userRegisterAsync(const QString &username, const QString &password)
{
    netClient.userRegister(username, password);
}

void DataCenter::phoneLoginAsync(const QString &phone, const QString &verifycode)
{
    netClient.phoneLogin(phone, this->currentVerifyCodeId, verifycode);
}

void DataCenter::phoneRegisterAsync(const QString &phone, const QString &verifyCode)
{
    netClient.phoneRegister(phone, this->currentVerifyCodeId, verifyCode);
}

void DataCenter::getSingleFileAsync(const QString &fileId)
{
    netClient.getSingleFile(loginSessionId, fileId);
}

void DataCenter::speechConvertTextAsync(const QString& fileId, const QByteArray &content)
{
    netClient.speechConvertText(loginSessionId, fileId, content);

}

ChatSessionInfo *DataCenter::findChatSessionById(const QString &chatSessionId)
{
    if (chatSessionList == nullptr)
    {
        return nullptr;
    }

    for (auto& info : *chatSessionList)
    {
        if (info.chatSessionId == chatSessionId)
        {
            return &info;
        }
    }
    return nullptr;
}

ChatSessionInfo *DataCenter::findChatSessionByUserId(const QString &userId)
{
    if (chatSessionList == nullptr)
    {
        return nullptr;
    }

    for (auto& info : *chatSessionList)
    {
        if (info.userId == userId)
        {
            return &info;
        }
    }
    return nullptr;
}

void DataCenter::topChatSessionInfo(const ChatSessionInfo &chatSessionInfo)
{
    // 把这个元素从列表中找到删除,并重新插入到头部
    if (chatSessionList == nullptr)
    {
        return;
    }
    // 1 找到元素
    auto it = chatSessionList->begin();
    for (; it != chatSessionList->end(); ++it)
    {
        if (it->chatSessionId == chatSessionInfo.chatSessionId)
        {
            break;
        }
    }
    if (it == chatSessionList->end())
    {
        //上面的循环没有找到匹配的元素,直接返回,正常来说,不会走这条逻辑
        return;
    }

    // 2 把这个元素备份一下
    ChatSessionInfo backup = chatSessionInfo;
    chatSessionList->erase(it);

    // 把备份元素, 插入到头部
    chatSessionList->push_front(backup);

}

void DataCenter::setCurrentChatsessionId(const QString &chatSessionId)
{
    this->currentChatSessionId = chatSessionId;
}

const QString &DataCenter::getCurrentChatSessionId()
{
    return this->currentChatSessionId;
}

void DataCenter::sendTextMessageAsync(const QString &chatSessionId, const QString &content)
{
    // 支持四种消息
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::TEXT_TYPE, content.toUtf8(), "");
}

void DataCenter::sendImageMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::IMAGE_TYPE, content, "");
}

void DataCenter::sendFileMessageAsync(const QString &chatSessionId, const QString &fileName, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::FILE_TYPE, content, fileName);
}

void DataCenter::sendSpeechMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::SPEECH_TYPE, content, "");
}

void DataCenter::changeNickName(const QString &nickname)
{
    netClient.changeNickName(loginSessionId, nickname);
}

void DataCenter::resetNickname(const QString &nickname)
{
    if (myself == nullptr) {
        return;
    }
    myself->nickname = nickname;
}

void DataCenter::changeDescriptionAsync(const QString &desc)
{
    netClient.changeDescription(loginSessionId, desc);
}

void DataCenter::resetDescription(const QString& desc)
{
    if (myself == nullptr) {
        return;
    }
    myself->description = desc;
}

void DataCenter::getVerifyCodeAsync(const QString &phone)
{
    //这个操作,不需要传入loginSessionId
    //后续还需要实现通过手机验证码登录,登录的时候没有loginSessionId的
    netClient.getVerifyCode(phone);
}

void DataCenter::resetVerifyCodeId(const QString &verifyCodeId)
{
    this->currentVerifyCodeId = verifyCodeId;
}

const QString &DataCenter::getVerifyCodeId()
{
    return this->currentVerifyCodeId;
}

void DataCenter::changePhoneAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.changePhone(loginSessionId, phone, verifyCodeId, verifyCode);
}

void DataCenter::resetPhone(const QString &phone)
{
    if (myself == nullptr) {
        return;
    }
    myself->phone = phone;
}

void DataCenter::changeAvatarAsync(const QByteArray &imageBytes)
{
    netClient.changeAvatar(loginSessionId, imageBytes);
}

void DataCenter::resetAvatar(const QByteArray &avatar)
{
    if (myself == nullptr) {
        return;
    }
    myself->avatar = makeIcon(avatar);
}

void DataCenter::deleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId, userId);
}

void DataCenter::removeFriend(const QString &userId)
{
    //遍历friendlist,删除其中匹配的元素即可
    if (friendList == nullptr || chatSessionList == nullptr) {
        return;
    }
    friendList->removeIf([=](const UserInfo& userInfo){
        // if (userInfo.userId == userId) {
        //     //该对象要删除
        //     return true;
        // }
        // return false;
        //返回ture要删除的元素,返回false直接跳过不删除
        return userInfo.userId == userId;
    });

    //还要考虑会话列表
    //没有好友,保留会话,后续往会话里发消息,不好处理
    //删除会话,客户端和服务器分别都会删除
    chatSessionList->removeIf([=](const ChatSessionInfo& chatSessionInfo){
        if (chatSessionInfo.userId == "") {
            //群里不受影响
            return false;
        }
        if (chatSessionInfo.userId == userId) {
            //确保当前会话要删除，并且要删除的会话又是选中的会话,才真正清空当前会话
            //如果删除的会话是正在选中的会话，此时就要把当前选中会话的内容(标题和消息列表)都清
            if (chatSessionInfo.chatSessionId == this->currentChatSessionId) {
                emit this->clearCurrentSession();
            }
            return true;
        }

        return false;

    });
}

void DataCenter::addFriendApplyAsync(const QString &userId)
{
    netClient.addFriendApply(loginSessionId, userId);
}

void DataCenter::acceptFriendApplyAsync(const QString &userId)
{

    netClient.acceptFriendApply(loginSessionId, userId);

}

UserInfo DataCenter::removeFromApplyList(const QString &userId)
{
    if (applyList == nullptr) {
        return UserInfo();
    }
    for (auto it = applyList->begin(); it != applyList->end(); ++it) {
        if (it->userId == userId) {
            //复制一下这个要删除的对象,以备进行返回
            UserInfo toDelete = *it;
            applyList->erase(it);
            return toDelete;
        }
    }
    return UserInfo();
}

void DataCenter::rejectFriendApplyAsync(const QString &userId)
{
    netClient.rejectFriendApply(loginSessionId, userId);
}

UserInfo* DataCenter::findFriendById(const QString &userId)
{
    if (this->friendList == nullptr) {
        return nullptr;
    }
        for (auto& f : *friendList) {
            if (f.userId == userId) {
                return &f;
            }
        }
        return nullptr;

}

void DataCenter::addMessage(const Message &message)
{
    QList<Message>& messageList = (*recentMessage)[message.chatSessionId];
    messageList.push_back(message);


}

void DataCenter::createGroupChatSessionAsync(const QList<QString> &userIdList)
{
    netClient.createGroupChatSession(loginSessionId, userIdList);
}

void DataCenter::getMemberListAsync(const QString &chatSessionId)
{
    netClient.getMemberList(loginSessionId, chatSessionId);
}

void DataCenter::resetMemberList(const QString &chatSessionId, const QList<shiyue_im::UserInfo> &memberList)
{
    //根据 chatSessionId, 这个key,得到对应的value(QList)
    QList<UserInfo>& currentMemberList = (*this->memberList)[chatSessionId];
    currentMemberList.clear();
    for (const auto& m : memberList) {
        UserInfo userInfo;
        userInfo.load(m);
        currentMemberList.push_back(userInfo);
    }
}

QList<UserInfo> *DataCenter::getMemberList(const QString& chatSessionId)
{
    if (!this->memberList->contains(chatSessionId)) {
        return nullptr;
    }
    return &(*this->memberList)[chatSessionId];
}

DataCenter *DataCenter::getInstance()
{
    if (instance == nullptr)
    {
        instance = new DataCenter();
    }

    return instance;
}


DataCenter::~DataCenter()
{
    //释放所有成员
    //此处不用判定nullptr, 直接delete;
    //c++ 标准明确规定,针对nullptr 进行delete 是合法行为, 不会有任何副作用
    delete myself;
    delete friendList;
    delete chatSessionList;
    delete memberList;
    delete applyList;
    delete recentMessage;
    delete unreadMessageCount;
    delete searchMessageResult;
    delete searchUserResult;


}
} // end namespace
